package com.scrm.exam.exception;

import cn.hutool.json.JSONUtil;
import com.scrm.exam.errorcode.ErrorCode;
import com.scrm.exam.response.Result;
import lombok.extern.slf4j.Slf4j;
import org.springframework.validation.BindException;
import org.springframework.validation.BindingResult;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.bind.annotation.RestControllerAdvice;
import org.springframework.web.multipart.MaxUploadSizeExceededException;
import org.springframework.web.multipart.MultipartException;
import org.springframework.web.util.ContentCachingRequestWrapper;

import javax.servlet.http.HttpServletRequest;
import java.io.InterruptedIOException;
import java.io.UnsupportedEncodingException;
import java.nio.charset.StandardCharsets;
import java.sql.SQLException;
import java.util.Map;

import static com.scrm.exam.utils.IOUtils.requestBodyArray;

/**
 * @author hqx
 */
@RestControllerAdvice
@Slf4j
public class GzsendiExceptionHandler {


    /**
     * 业务异常
     *
     * @param e       异常
     * @param request 请求
     * @return 业务异常
     */
    @ExceptionHandler(GzsendiException.class)
    @ResponseBody
    public Result<Object> handlerBusinessException(GzsendiException e, HttpServletRequest request) {
        log.error("业务异常e:{}, URL: {}, 参数：{}", e, JSONUtil.toJsonStr(request.getRequestURI()), requestBody(request));
        return new Result<>(e.getCode(), e.getMessage());
    }

    /**
     * 数据请求或数据库异常
     *
     * @param e       异常
     * @param request 请求
     * @return 数据异常
     */
    @ExceptionHandler({SQLException.class})
    @ResponseBody
    public Result<Map<String, Object>> handlerDataException(SQLException e, HttpServletRequest request) {
        log.error("数据异常e:{}, URL: {}, 参数：{}", e, JSONUtil.toJsonStr(request.getRequestURI()), requestBody(request));
        return new Result<>(ErrorCode.ERR_502_SQL.getCode(), ErrorCode.ERR_502_SQL.getMessage());
    }


    /**
     * 网络超时
     *
     * @param e       异常
     * @param request 请求
     * @return 网络超时异常
     */
    @ExceptionHandler({InterruptedIOException.class})
    @ResponseBody
    public Result<Map<String, Object>> handlerTimeoutException(InterruptedIOException e, HttpServletRequest request) {
        log.error("网络超时e:{}, URL: {}, 参数：{}", e, JSONUtil.toJsonStr(request.getRequestURI()), requestBody(request));

        return new Result<>(ErrorCode.ERR_505_TIMEOUT.getCode(), ErrorCode.ERR_505_TIMEOUT.getMessage());
    }

    /**
     * 数据请求或数据库异常
     *
     * @param e       异常
     * @param request 请求
     * @return 请求异常
     */
    @ExceptionHandler({BindException.class})
    @ResponseBody
    public Result<Object> handlerBindingException(BindException e, HttpServletRequest request) {
        log.error("绑定参数异常e:{}, URL: {}, 参数：{}", e, JSONUtil.toJsonStr(request.getRequestURI()), requestBody(request));
        BindingResult bindingResult = e.getBindingResult();
        return new Result<>(500, "参数绑定异常");
    }


    /**
     * 处理文件上传大小超限制
     *
     * @param e
     * @return
     */
    @ExceptionHandler({MaxUploadSizeExceededException.class})
    @ResponseBody
    public Result<Object> fileUploadExceptionHandler(MultipartException e, HttpServletRequest request) {
        log.error("处理文件上传大小超限制e:{}, URL: {}, 参数：{}", e, JSONUtil.toJsonStr(request.getRequestURI()), requestBody(request));
        return new Result<>(ErrorCode.ERR_506_FILE_SIZE_EXCEEDED.getCode(), ErrorCode.ERR_506_FILE_SIZE_EXCEEDED.getMessage());
    }


    /**
     * 其它异常
     *
     * @param e       异常
     * @param request 请求参数
     * @return 返回异常报错
     */
    @ExceptionHandler(Exception.class)
    @ResponseBody
    public Result<Map<String, Object>> handlerThrowable(Throwable e, HttpServletRequest request) {
        log.error("全局异常e:{},  URL: {}, 参数：{}", JSONUtil.toJsonStr(request.getRequestURI()), requestBody(request));
        return new Result<>(ErrorCode.ERR_500_FAILURE.getCode(), ErrorCode.ERR_500_FAILURE.getMessage());
    }


    public static String requestBody(HttpServletRequest request) {
        byte[] bytes = requestBodyArray(request);
        if (bytes.length > 0) {
            if (ContentCachingRequestWrapper.class.isAssignableFrom(request.getClass())) {
                ContentCachingRequestWrapper requestWrapper = ((ContentCachingRequestWrapper) (request));
                try {
                    return new String(bytes, requestWrapper.getCharacterEncoding());
                } catch (UnsupportedEncodingException e) {
                }
            }

            return new String(bytes, StandardCharsets.UTF_8);
        }
        return "";
    }
}
